#ifndef RECORD_H
#define RECORD_H

#include "str.h"
#include "table.h"
#include <string>
#include <vector>
#include <iostream>
#include <map>

using namespace std;

class Record {
private:
    Table table;
    vector<unsigned int> record;

    map<string, string> getRecordMap() {
        map<string, string> ret;
        vector<Table::Segment> segments = table.getSegments();

        int cnt = 0;
        for (int i = 0; i < segments.size(); i++) {
            string key = segments[i].key;
            string value = "";

            bool isNull = false;
            if (segments[i].type == 0) {
                for (int j = 0; j < segments[i].length; j++) {
                    if (0 <= record[cnt] && record[cnt] <= 9) {
                        value += (char)('0' + record[cnt++]);
                    } else {
                        isNull = true;
                    }
                }
                value = Str::removeLeadingZero(value);
                if (value == "") {
                    value = "0";
                }
            } else if (segments[i].type == 1) {
                for (int j = 0; j < segments[i].length; j++) {
                    value += (char)record[cnt++];
                }
                value = Str::removeFollowingSpace(value);
                if (value == "") {
                    isNull = true;
                }
            } else if (segments[i].type == 2) {
                for (int j = 0; j < segments[i].length; j++) {
                    char ch = record[cnt++];
                    if (0 <= ch && ch <= 9) {
                        value += (char)('0' + ch);
                    } else if (ch == '.') {
                        value += ch;
                    } else {
                        isNull = true;
                    }
                }
                value = Str::removeLeadingZero(value);
                if (value[0] == '.') {
                    value = "0" + value;
                } else if (value[value.length() - 1] == '.') {
                    value = value.substr(0, value.length() - 1);
                }
                if (value == "") {
                    value = "0";
                }
            } else {
                cout << "Unknown type in Record::getRecordMap" << endl;
            }

            if (isNull) {
                value = "null";
            }
            ret[key] = value;
        }

        return ret;
    }

    vector<unsigned int> formValueData(Table::Segment seg, string value) {
        vector<unsigned int> valueData;

        if (seg.type == 0) { //int(len)
            if (value == "null" || value == "NULL") {
                //ascii [10, 10, 10, ...] for NULL
                for (int j = 0; j < seg.length; j++) {
                        valueData.push_back(10);
                }
            } else if (value.length() <= seg.length) {
                for (int j = 0; j < seg.length - value.length(); j++) {
                    valueData.push_back(0);
                }
                for (int j = 0; j < value.length(); j++) {
                    if ('0' <= value[j] && value[j] <= '9') {
                        valueData.push_back(value[j] - '0');
                    } else {
                        cout << "Not a int error in Record::formValueData" << endl;
                    }
                }
            } else {
                for (int j = 0; j < seg.length; j++) {
                    valueData.push_back(value[j - seg.length + value.length()] - '0');
                }
                cout << "Int too long in Record::formValueData" << endl;
            }
        } else if (seg.type == 1){ //varchar(len)
            if (value == "null") {
                for (int j = 0; j < seg.length; j++) {
                    valueData.push_back((unsigned int)(' '));
                }
            } else {
                value = Str::removeChar(value, '\'');

                if (value.length() <= seg.length) {
                    for (int j = 0; j < value.length(); j++) {
                        valueData.push_back((unsigned int)value[j]);
                    }
                    for (int j = 0; j < seg.length - value.length(); j++) {
                        valueData.push_back((unsigned int)(' '));
                    }
                } else {
                    for (int j = 0; j < seg.length; j++) {
                        valueData.push_back(value[j] - '0');
                    }
                    cout << "Varchar too long in Record::formValueData" << endl;
                }
            }
        } else if (seg.type == 2) {
            if (value == "null") {
                //ascii [10, 10, 10, ...] for NULL
                for (int j = 0; j < seg.length; j++) {
                    valueData.push_back(10);
                }
            } else if (value.length() <= seg.length) {
                for (int j = 0; j < seg.length - value.length(); j++) {
                    valueData.push_back(0);
                }
                bool existDot = false;
                for (int j = 0; j < value.length(); j++) {
                    if (value[j] == '.') {
                        if (existDot) {
                            valueData.push_back(0);
                            cout << "Not a decimal error in Record::formValueData" << endl;
                        } else {
                            valueData.push_back('.');
                            existDot = true;
                        }
                    } else if ('0' <= value[j] && value[j] <= '9') {
                        valueData.push_back(value[j] - '0');
                    } else {
                        cout << "Not a decimal error in Record::formValueData" << endl;
                    }
                }
            } else {
                for (int j = 0; j < seg.length; j++) {
                    valueData.push_back(0);
                }
                cout << "Decimal too long in Record::formValueData" << endl;
            }
        } else {
            cout << "Unknown type in Record::formValueData" << endl;
        }

        return valueData;
    }

public:
    Record(Table table) {
        this->table = table;

        int recordLen = table.getRecordLen();

        record.clear();
        for (int i = 0; i < recordLen; i++) {
            record.push_back(0);
        }
    }

    int getLength() {
        return record.size();
    }

    string getPrimaryValue() {
        return find(table.getPrimaryKey());
    }

    void setData(vector<unsigned int> data) {
        if (data.size() == record.size()) {
            record = data;
        } else {
            cout << "Size do not match in Record::setData" << endl;
        }
    }

    vector<unsigned int> getData() {
        return record;
    }

    void setExpression(string expression) {
        //SAMPLE RECORD:
        //(100008,'Oxbow Books Limited','CA')
        //according to table:
        //CREATE TABLE publisher (
        //  id int(10) NOT NULL,
        //  name varchar(100) NOT NULL,
        //  state varchar(2),
        //  PRIMARY KEY  (id)
        //);
        record.clear();
        expression = Str::between(expression, "(", ")");
        vector<string> segmentExpressions = Str::split(expression, ",");

        vector<Table::Segment> segments = table.getSegments();
        if (segmentExpressions.size() == segments.size()) {
            for (int i = 0; i < segments.size(); i++) {
                string value = Str::removeChar(segmentExpressions[i], ' ');

                vector<unsigned int> valueData = formValueData(segments[i], value);
                for (int j = 0; j < valueData.size(); j++) {
                    record.push_back(valueData[j]);
                }
            }
        } else {
            cout << "Segment number do not match in Record::setExpression" << endl;
        }
    }

    void setAttrValue(vector<string> segmentExpressions) {
        record.clear();

        vector<Table::Segment> segments = table.getSegments();

        if (segmentExpressions.size() == segments.size()) {
            for (int i = 0; i < segments.size(); i++) {
                string value = Str::removeChar(segmentExpressions[i], ' ');

                //cout << segmentExpressions[i] << " ";
                vector<unsigned int> valueData = formValueData(segments[i], segmentExpressions[i]);
                for (int j = 0; j < valueData.size(); j++) {
                    record.push_back(valueData[j]);
                }
            }
            //cout << endl;
        } else {
            cout << "Segment number do not match in Record::setAttrValue" << endl;
        }
    }

    void output() {

        map<string, string> recordMap = getRecordMap();
        for (map<string, string>::iterator iter = recordMap.begin(); iter != recordMap.end(); iter++) {
            if (iter != recordMap.begin()) {
                cout << " ";
            }
            cout << iter->second;
        }

    }

    string find(string key) {
        map<string, string> recordMap = getRecordMap();
        return recordMap[key];
        /*vector<Table::Segment> segments = table.getSegments();

        int cnt = 0;
        for (int i = 0; i < segments.size(); i++) {
            if (segments[i].key == key) {
                string value = "";

                bool isNull = false;
                if (segments[i].type == 0) {
                    for (int j = 0; j < segments[i].length; j++) {
                        if (record[cnt] < 0 || record[cnt] > 9) {
                            isNull = true;
                        }
                        value += (char)('0' + record[cnt++]);
                    }
                    value = Str::removeLeadingZero(value);
                } else if (segments[i].type == 1) {
                    for (int j = 0; j < segments[i].length; j++) {
                        value += (char)record[cnt++];
                    }
                    value = Str::removeFollowingSpace(value);
                    if (value == "") {
                        isNull = true;
                    }
                } else {
                    cout << "Unknown type in Record::find" << endl;
                }

                if (isNull) {
                    return "NULL";
                }
                return value;
            }
            cnt += segments[i].length;
        }

        return "NULL";*/
    }

    void update(string key, string value) {
        vector<Table::Segment> segments = table.getSegments();

        int cnt = 0;
        for (int i = 0; i < segments.size(); i++) {
            if (segments[i].key == key) {
                vector<unsigned int> valueData = formValueData(segments[i], value);
                for (int j = 0; j < valueData.size(); j++) {
                    record[cnt++] = valueData[j];
                }
                return;
            }
            cnt += segments[i].length;
        }

        cout << "Key not found error in Record::find" << endl;
    }

    bool notNullError() {
        map<string, string> recordMap = getRecordMap();
        vector<Table::Segment> segments = table.getSegments();

        for (int i = 0; i < segments.size(); i++) {
            if (segments[i].notNull && recordMap[segments[i].key] == "null") {
                return true;
            }
        }

        return false;
    }
};

#endif
